home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 123_01 / pp.c < prev    next >
Text File  |  1985-03-09  |  14KB  |  642 lines

  1.  /*******************************************************\
  2. **    A preprocessor using the "C" syntax        **
  3. **    described by K&R in "The C Programming        **
  4. **    Language."  Based on the macro processor    **
  5. **    in Ratfor from K&P's "Software Tools."        **
  6. **                            **
  7. **    Robert T Pasky                    **
  8. **    36 Wiswall Rd                    **
  9. **    Newton Centre, MA 02159                **
  10. **    (617) 964-3641                    **
  11.  \*******************************************************/
  12.  
  13. /*
  14. **    format is:
  15. **        pp <infile> [<outfile>] [-d]\n");
  16. **
  17. **    if <outfile> is not given, output will be placed in
  18. **    <infile>.PP.
  19. **    The optional -d turns on the debug mode which is only
  20. **    useful if you want to watch what goes on inside the
  21. **    program as it crunches files.
  22. **
  23. **    This version is not simply a translation from the
  24. **    Ratfor version: it was modified to conform to the
  25. **    "official" format of the C preprocessor as defined
  26. **    in the K&R C Programming Language book.
  27. **    The output file can be fed into the BDS C compiler;
  28. **    or any other compiler (and other languages?) for
  29. **    which the input was intended.
  30. **
  31. **    This program has #include file capability and
  32. **    symbolic parameter substitution. That means you
  33. **    can write something like:
  34. **        #define max(a,b) (a) > (b) ? (a) : (b)
  35. **    which will replace:
  36. **        max(x+1,y-1)
  37. **    with:
  38. **        (x+1) > (y-1) ? (x+1) : (y-1)
  39. **
  40. **    Here "max(a,b)" is a template with two parameters:
  41. **    a and b. When the preprocessor sees "max(x+1,y-1)"
  42. **    it replaces the first parameter (a) in the definition
  43. **    with "x+1" and the second parameter ("b") with "y-1".
  44. **    Notice that the "(" must follow "max" with no intervening
  45. **    spaces. That's so the preprocessor can differentiate
  46. **    between argumented and non-argumented macros, e.g.,
  47. **    "#define ERROR (-1)".
  48. **    Secondly, the a and b in the definition are surrounded
  49. **    by parentheses. This is often a good idea; it avoids
  50. **    problems that might occur with precedence rules, e.g.:
  51. **    #define div(a,b) a/b
  52. **    ... div(x+2,5)
  53. **    would result in "x+2/5" which is interpreted as x+(2/5)
  54. **    instead of the intended "(x+2)/5".
  55. **
  56. **    Note: this program has NOT been rigorously tested
  57. **    and, as provided here, is quite limited in its array
  58. **    size (it's easy enough to increase the defines for
  59. **    the array sizes if you have lots of memory).
  60. **    The proportions allocated among the various arrays
  61. **    may also need tuning. For example, if you like to use
  62. **    lots of short define strings you might increase MAXTOK
  63. **    and MAXDEF. On the other hand, if you have relatively
  64. **    few defines but they tend to be long-winded, you could
  65. **    shorten these in favor of increasing MAXTBL (and
  66. **    possibly DEFSIZ).
  67. */
  68.  
  69. #include "bdscio.h"
  70.  
  71. #define STDOUT 1
  72.  
  73. #define STDERR 1    /* EKR 3/10/83 */
  74. #define YES 1        /* EKR 3/10/83 */
  75. #define NO 0        /* EKR 3/10/83 */
  76. #define NUL NULL    /* EKR 3/10/83 */
  77. #define EQUAL 0        /* EKR 3/10/83 */
  78.  
  79. #define ALPHA 'a'
  80. #define LETTER 'a'
  81. #define DIGIT '9'
  82. #define LPAREN '('
  83. #define RPAREN ')'
  84. #define LBRACK '('
  85. #define RBRACK ')'
  86. #define COMMA ','
  87. #define ARGFLAG 0xFA
  88. #define HASH '#'
  89. #define DEFTYPE 0xFC
  90. #define INCTYPE 0xFB
  91. #define MAXFILNAME 20
  92. #define CHARBUFSIZE 80
  93. #define MAXDEF 600
  94. #define MAXTOK 200
  95. #define MAXTBL 1000
  96. #define MAXPTR 600
  97. #define DEFSIZ 129
  98. #define TOKSIZ 129
  99. #define EVALSIZE 200
  100. #define ARGSIZE 200
  101. #define CALLSIZE 200
  102.  
  103. int bp;
  104. char buf[CHARBUFSIZE];
  105. char inbuf[BUFSIZ], incbuf[BUFSIZ], outbuf[BUFSIZ];
  106. char outfile[MAXFILNAME], incfil[MAXFILNAME];
  107. char defn[MAXDEF], token[MAXTOK], table[MAXTBL];
  108. int namptr[MAXPTR];
  109. int lastp, lastt;
  110. int cp, ep;
  111. char evalst[EVALSIZE];
  112. int ap, argstk[ARGSIZE], callst[CALLSIZE];
  113. int nlb, plev[CALLSIZE];
  114. int incflg;
  115.  
  116. int debug;
  117.  
  118. main(argc, argv)
  119. int argc;
  120. char **argv;
  121. {
  122. /*
  123. **    macro - expand macros with arguments
  124. */
  125.     char t, *defnam, *incnam, *s;
  126.     int deftyp[2];
  127.     char *balp;
  128.  
  129.     debug = FALSE;
  130.     deftyp[0] = DEFTYPE;
  131.     deftyp[1] = NUL;
  132.     defnam = "#define";
  133.     incnam = "#include";
  134.     incflg = NO;
  135.     balp = "()";
  136.     bp = -1;
  137.     lastp = lastt = -1;
  138.  
  139.     printf("pp v1.0\n");
  140.  
  141.     if (argc < 2)
  142.         perr("usage: pp <infile> [<outfile>] [-d]\n");
  143.     s = *++argv;
  144.     if (fopen(s, inbuf) == ERROR)
  145.         perr1("cannot open <%s>", s);
  146.     argc -= 2; argv++;
  147.     if (argc > 0 && **argv != '-') {
  148.         strcpy (outfile, s = *argv++);
  149.         argc--;
  150.         }
  151.     else    {
  152.         strcpy (outfile, s);
  153.         strcat (outfile, ".PP");
  154.         }
  155.     if (fcreat(outfile, outbuf) == ERROR)
  156.         perr1("cannot create <%s>", outfile);
  157.     fprintf(STDERR, "output will be in <%s>\n", outfile);
  158.  
  159.     while (argc-- > 0) {
  160.         s = *argv++;
  161.         if (strcmp(s, "-D") == EQUAL)
  162.             debug = TRUE;
  163.         }
  164.     if (debug) fprintf(STDERR,"debug is on\n");
  165.  
  166.     instal(defnam, deftyp);
  167.     deftyp[0] = INCTYPE;
  168.     instal(incnam, deftyp);
  169.     cp = -1;
  170.     ap = ep = 0;
  171.     for (t = gettok(); t != CPMEOF; t = gettok()) {
  172.         if (t == ALPHA) {
  173.             if (lookup(token, defn) == NO)
  174.                 puttok(token);
  175.             else {
  176.                 if (*defn == INCTYPE) {
  177.                     doinc();
  178.                     continue;
  179.                     }
  180.                 if (++cp > CALLSIZE)
  181.                     perr("call stack overflow\n");
  182.                 callst[cp] = ap;
  183.                 ap = push(ep, argstk, ap);
  184.                 puttok(defn);
  185.                 putchr(NUL);
  186. if (debug) fprintf(STDERR, "push defn: <%s>\n", defn);
  187.                 ap = push(ep, argstk, ap);
  188. /*********************/
  189.                 if (*defn == DEFTYPE)
  190.                     while (isspace(gettok()))
  191.                         ;
  192. /*********************/
  193.                 puttok(token);
  194.                 putchr(NUL);
  195. if (debug) fprintf(STDERR, "push name: <%s>\n", token);
  196.                 ap = push(ep, argstk, ap);
  197.                 t = gettok();
  198.                 pbstr(token);
  199. if (debug) fprintf(STDERR, "next token: <%s>\n", token);
  200.                 if (t != LPAREN)
  201.                     pbstr(balp);    /* add () if none */
  202.                 plev[cp] = 0;
  203.                 }
  204.             }
  205.         else if (cp == -1)
  206.             puttok(token);
  207. /*        else if (t == LBRACK) {
  208. **            nlb = 1;
  209. **            while (1) {
  210. **                t = gettok();
  211. **                if (t == LBRACK)
  212. **                    nlb++;
  213. **                else if (t == RBRACK) {
  214. **                    nlb--;
  215. **                    if (nlb == 0)
  216. **                        break;
  217. **                    }
  218. **                else if (t == CPMEOF)
  219. **                    perr("EOF in string\n");
  220. **                puttok(token);
  221. **                }
  222. **            }
  223. */
  224.         else if (t == LPAREN) {
  225.             if (plev[cp]++ > 0)
  226.                 puttok(token);
  227.             }
  228.         else if (t == RPAREN) {
  229.             if (--plev[cp] > 0)
  230.                 puttok(token);
  231.             else {
  232.                 putchr(NUL);
  233.                 eval(argstk, callst[cp], ap - 1);
  234.                 ap = callst[cp];    /* pop eval stack */
  235.                 ep = argstk[ap];
  236.                 cp--;
  237.                 }
  238.             }
  239.         else if (t == COMMA && plev[cp] == 1) {
  240.             putchr(NUL);
  241.             ap = push(ep, argstk, ap);
  242.             }
  243.         else
  244.             puttok(token);
  245.         }
  246.     if (cp != -1)
  247.         perr("unexpected EOF (not at level 0)\n");
  248.  
  249.     putc(CPMEOF, outbuf);
  250.     fflush(outbuf);
  251.     fclose(outbuf);
  252.     exit();
  253. }
  254.  
  255. perr(s)
  256. char *s;
  257. {
  258.     fprintf(STDERR, s);
  259.     exit();
  260. }
  261.  
  262. perr1(s, t)
  263. char *s, *t;
  264. {
  265.     fprintf(STDERR, s, t);
  266.     exit();
  267. }
  268. /*
  269. **    lookup - locate name, extract def. from table
  270. */
  271. lookup(name, defn)
  272. char name[], defn[];
  273. {
  274.     int i, j, k;
  275.  
  276. if(debug) fprintf(STDERR, "lookup: name <%s>...", name);
  277.  
  278.     for (i = lastp; i >= 0; i--) {
  279.  
  280. if(debug) fprintf(STDERR, "\nnamptr: %d table: <%s>",
  281.      namptr[i], &table[namptr[i]]);
  282.  
  283.         if (strcmp(&table[namptr[i]], name) == EQUAL) {
  284.             j = strlen(name) + 1;
  285.             strcpy (defn, &table[namptr[i] + j]);
  286.  
  287. if(debug) fprintf(STDERR, "found! defn: <%s>\n", defn);
  288.  
  289.             return(YES);
  290.             }
  291.         }
  292. if(debug) fprintf(STDERR, "not found.\n");
  293.  
  294.     return(NO);
  295. }
  296.  
  297. /*
  298. **    instal - add name and definition to table
  299. */
  300. instal(name, defn)
  301. char name[], defn[];
  302. {
  303.     int dlen, nlen;
  304.  
  305. if(debug) fprintf(STDERR, "instal: name <%s> defn <%s>\n", name, defn);
  306.  
  307.     nlen = strlen(name) + 1;
  308.     dlen = strlen(defn) + 1;
  309.     if (lastt + nlen + dlen > MAXTBL || lastp >= MAXPTR)
  310.         fprintf(STDERR, "<%s>: too many defns\n", name);
  311.  
  312.     namptr[++lastp] = lastt + 1;
  313.     strcpy(&table[lastt + 1], name);
  314.     strcpy(&table[lastt + nlen + 1], defn);
  315.     lastt += nlen + dlen;
  316. }
  317.  
  318. /*
  319. **    getdef - for no arguments - get name and definition
  320. */
  321. getdef(token, defn)
  322. char token[], defn[];
  323. {
  324.     int i, nlpar;
  325.     char c;
  326.  
  327. if(debug) fprintf(STDERR, "getdef: token <%s>\n", token);
  328.  
  329.     if ((c = ngetc()) != LPAREN)
  330.         perr("missing left paren\n");
  331.     else if (gettok() != ALPHA)
  332.         perr("non-alphanumeric token\n");
  333.     else if ((c = ngetc()) != COMMA)
  334.         perr("missing comma in